
///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008, Arizona State University
//  All rights reserved.
//  BSD License: http://www.opensource.org/licenses/bsd-license.html
//  Created by: Adam Kubach
//
///////////////////////////////////////////////////////////////////////////////

#include "Minerva/Core/Data/Feature.h"
#include "Minerva/Core/Data/TimeSpan.h"
#include "Minerva/Core/Visitor.h"

#include "Usul/File/Temp.h"
#include "Usul/Threads/Safe.h"

using namespace Minerva::Core::Data;

USUL_IMPLEMENT_IUNKNOWN_MEMBERS ( Feature, Feature::BaseClass );

/////////////////////////////////////////////////////////////////////////////
//
//  Declare serialization wrappers.
//
/////////////////////////////////////////////////////////////////////////////

USUL_IO_TEXT_DEFINE_READER_TYPE_VECTOR_4 ( Feature::Extents );
USUL_IO_TEXT_DEFINE_WRITER_TYPE_VECTOR_4 ( Feature::Extents );
SERIALIZE_XML_DECLARE_VECTOR_4_WRAPPER ( Feature::Extents );


///////////////////////////////////////////////////////////////////////////////
//
//  Constructor.
//
///////////////////////////////////////////////////////////////////////////////

Feature::Feature() : 
  BaseClass(),
  _description(),
  _name(),
	_styleUrl(),
  _visibility(),
  _lookAt ( 0x0 ),
  _timePrimitive ( 0x0 ),
  _extents(),
  _dataChangedListeners()
{
  _visibility.fetch_and_store ( true );
  this->_addMember ( "name", _name.getReference() );
  this->_addMember ( "visibility", _visibility );
  this->_addMember ( "extents", _extents );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Constructor.
//
///////////////////////////////////////////////////////////////////////////////

Feature::Feature ( const Feature& rhs ) : BaseClass ( rhs ),
  _description( rhs._description ),
  _name( rhs._name ),
  _styleUrl( rhs._styleUrl ),
  _visibility ( rhs._visibility ),
  _lookAt ( rhs._lookAt ),
  _timePrimitive ( rhs._timePrimitive ),
  _extents ( rhs._extents ),
  _dataChangedListeners()
{
  this->_addMember ( "name", _name.getReference() );
  this->_addMember ( "visibility", _visibility );
  this->_addMember ( "extents", _extents );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destructor.
//
///////////////////////////////////////////////////////////////////////////////

Feature::~Feature()
{
}


///////////////////////////////////////////////////////////////////////////////
//
//  Query for interface.
//
///////////////////////////////////////////////////////////////////////////////

Usul::Interfaces::IUnknown* Feature::queryInterface ( unsigned long iid )
{
  return 0x0;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Accept the visitor.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::accept ( Minerva::Core::Visitor& visitor )
{
  visitor.visit ( *this );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the name.
//
///////////////////////////////////////////////////////////////////////////////

std::string Feature::name() const
{
  return _name;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the name.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::name ( const std::string& name )
{
  // Set the name.
  this->_nameSet ( name );

  // Notify any listeners that the data has changed.
  this->_notifyDataChangedListeners();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the name.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::_nameSet ( const std::string& name )
{
  _name = name;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the visiblity.
//
///////////////////////////////////////////////////////////////////////////////

bool Feature::visibility() const
{
  return _visibility;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the visiblity.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::visibilitySet ( bool b )
{
  _visibility.fetch_and_store ( b );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the style url.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::styleUrl ( const std::string& url )
{
  Guard guard ( this->mutex() );
	_styleUrl = url;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the style url.
//
///////////////////////////////////////////////////////////////////////////////

std::string Feature::styleUrl() const
{
  Guard guard ( this->mutex() );
	return _styleUrl;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the time primitive.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::timePrimitive ( TimePrimitive* timePrimitive )
{
  Guard guard ( this->mutex() );
  _timePrimitive = timePrimitive;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the time primitive.
//
///////////////////////////////////////////////////////////////////////////////

Minerva::Core::Data::TimePrimitive* Feature::timePrimitive() const
{
  Guard guard ( this->mutex() );
  return _timePrimitive.get();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the description.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::description ( const std::string& s )
{
  Guard guard ( this->mutex() );
  _description = s;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the description.
//
///////////////////////////////////////////////////////////////////////////////

std::string Feature::description() const
{
  Guard guard ( this->mutex() );
  return _description;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the look at.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::lookAt ( LookAt* lookAt )
{
  Guard guard ( this->mutex() );
  _lookAt = lookAt;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the look at.
//
///////////////////////////////////////////////////////////////////////////////

LookAt* Feature::lookAt() const
{
  Guard guard ( this->mutex() );
  return _lookAt.get();
}


/////////////////////////////////////////////////////////////////////////////////
//
//  Add the listener.  Note: No need to guard, _dataChangedListeners has it's own mutex.
//
///////////////////////////////////////////////////////////////////////////////

Feature::Connection Feature::addDataChangedListener ( const ModifiedCallback& caller )
{
  return _dataChangedListeners.connect ( caller );
}


/////////////////////////////////////////////////////////////////////////////////
//
//  Remove the listener.  Note: No need to guard, _dataChangedListeners has it's own mutex.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::removeDataChangedListener ( const Connection& connection )
{
  _dataChangedListeners.disconnect ( connection );
}


///////////////////////////////////////////////////////////////////////////////
//
//   Notify data changed listeners.  Note: No need to guard, _dataChangedListeners has it's own mutex.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::_notifyDataChangedListeners()
{
  _dataChangedListeners();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Set the extents.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::extents ( const Extents& e )
{
  Guard guard ( this->mutex() );
  _extents = e;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the extents.
//
///////////////////////////////////////////////////////////////////////////////

Feature::Extents Feature::extents() const
{
  return Usul::Threads::Safe::get ( this->mutex(), _extents );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Update the extents.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::_updateExtents ( Feature *feature )
{
  if ( feature )
  {
    Guard guard ( this->mutex() );
    _extents.expand ( feature->extents() );
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Update the extents.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::_expandExtents ( const Extents& extents )
{
  _extents.expand ( extents );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the number of children (ITreeNode).
//
///////////////////////////////////////////////////////////////////////////////

unsigned int Feature::getNumChildNodes() const
{
  return 0;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the child node (ITreeNode).
//
///////////////////////////////////////////////////////////////////////////////

Feature::RefPtr Feature::getChildNode ( unsigned int which )
{
  return Feature::RefPtr ( 0x0 );
}


///////////////////////////////////////////////////////////////////////////////
//
//  See if the given level falls within this layer's range of levels.
//
///////////////////////////////////////////////////////////////////////////////

bool Feature::isInLevelRange ( unsigned int level ) const
{
  return true;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Update.
//
///////////////////////////////////////////////////////////////////////////////

void Feature::updateNotify ( CameraState* camera, Minerva::Common::IPlanetCoordinates *planet, Minerva::Common::IElevationDatabase *elevation )
{
}
